#ifndef SBTNODE_H_INCLUDED
#define SBTNODE_H_INCLUDED

#include "SbtPrerequisites.h"
#include "SbtVector2.h"
#include "SbtStableHeader.h"

namespace Sbt
{

enum TransformSpace {
    RelativeToLocal,
    RelativeToParent,
    RelativeToWorld,
};

class Node
{
public:
    Node();
    Node(const String& name);
    Node(const String& name, Node* parent);

    virtual ~Node();

    void addChildNode(Node* child, 
        const Vector2& translate = Vector2::Zero,
        const float rotate = 0.0f);

    void setParentNode(Node* parent);
    Node* getParentNode() const;

    Node* getNode(const String& name) const;

    virtual void update();

    void updateRequestedChildren();
    void updateAllChildren();

    void requestUpdate(Node* child);

    const float getZOrderValue() const { return mZOrderValue; }
    void setZOrderValue(const float value) { mZOrderValue = value; }

    const Vector2& getRelativePosition() const { return mRelativePosition; }
    const Vector2& getRelativeScale() const { return mRelativeScale; }
    const float getRelativeRotation() const { return mRelativeRotation; }

    void setRelativePosition(const Vector2& position) 
    {
        mRelativePosition = position; 
        needUpdate();
    }

    void setRelativePosition(const float x, const float y) 
    { 
        mRelativePosition = Vector2(x, y); 
        needUpdate();
    }

    void setRelativeRotation(const float rotation) 
    {
        mRelativeRotation = rotation; 
        needUpdate();
    }

    void setRelativeScale(const Vector2& scale) 
    { 
        mRelativeScale = scale; 
        needUpdate();
    }

    void setRelativeScale(const float x, const float y) 
    {
        mRelativeScale = Vector2(x, y); 
        needUpdate();
    }

    void translate(const Vector2& translation, TransformSpace relative);
    void translate(const float x, const float y, TransformSpace relative);
    void rotate(const float rotation, TransformSpace relative);
    void scale(const Vector2& scale);
    void scale(const float x, const float y);

    void setDerivedPosition(const Vector2& position);
    void setDerivedRotation(const float rotation);
    void setDerivedScale(const Vector2& scale);

    const Vector2& getDerivedPosition() const;
    const Vector2& getDerivedScale() const;
    const float getDerivedRotation() const;

protected:
    void needUpdate();
    void setUpdated() const;

    void updateDerivedData() const;

protected:
    float mZOrderValue;

    Vector2 mRelativePosition;
    Vector2 mRelativeScale;
    float mRelativeRotation;

    mutable Vector2 mDerivedPosition;
    mutable Vector2 mDerivedScale;
    mutable float mDerivedRotation;

    mutable bool mNeedUpdateDerivedData;
    bool mNeedUpdateAllChildren;

    String mName;

    Node* mParentNode;

    typedef std::map< String, Node* > ChildNodeMap;
    ChildNodeMap mChildNodeMap;

    typedef std::set<Node*> NeedUpdateChildrenSet;
    NeedUpdateChildrenSet mChildrenNeedUpdate;
};

} // namespace Sbt

#endif // SBTNODE_H_INCLUDED